﻿using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Linq;

namespace FluentResourceMapping
{
    public abstract class TypeResourceMap<T> : ResourceMap
    {
        private TypeResourceMapping _mapping = new TypeResourceMapping(typeof (T));

        protected virtual TypeResourceMapping Mapping
        {
            get { return _mapping; }
            set { _mapping = value; }
        }

        private static MemberInfo GetMember<TValue>(Expression<Func<T, TValue>> memberExpression)
        {
            if (memberExpression == null) throw new ArgumentNullException("memberExpression");

            MemberExpression me = memberExpression.Body as MemberExpression;

            if (me == null) throw new ArgumentException("Invalid property selector", "memberExpression");

            return me.Member;
        }

        public void Map<TValue>(Expression<Func<T, TValue>> memberExpression, Type resourceType, string resourceName)
        {
            if (resourceType == null) throw new ArgumentNullException("resourceType");
            if (resourceName == null) throw new ArgumentNullException("resourceName");

            // Does not allow repeated member mappings
            if (Mapping.MemberResourceMappings.Any(o => o.Member == GetMember(memberExpression)))
            {
                Mapping.MemberResourceMappings.Remove(
                    Mapping.MemberResourceMappings.Single(o => o.Member == GetMember(memberExpression)));
            }

            Mapping.MemberResourceMappings.Add(new MemberResourceMapping(GetMember(memberExpression), resourceType,
                                                                         resourceName));
        }

        public void Map<TValue>(Expression<Func<T, TValue>> memberExpression,
                                Expression<Func<string>> resourceMemberExpression)
        {
            var resMember = resourceMemberExpression.Body as MemberExpression;
            if (resMember == null)
                throw new ArgumentException("Invalid resource property selector", "resourceMemberExpression");

            Map(memberExpression, resMember.Member.DeclaringType, resMember.Member.Name);
        }

        public MapWithResourceType<T> WithResourceType(Type resourceType)
        {
            return new MapWithResourceType<T>(resourceType, this);
        }

        public override TypeResourceMapping GetResourceMapping()
        {
            return Mapping;
        }

        public override Type GetClassType()
        {
            return typeof (T);
        }
    }


    //TODO: Separar pra outro arquivo
    public class MapWithResourceType<T>
    {
        private readonly Type _resourceType;
        private readonly TypeResourceMap<T> _typeResourceMap;

        public MapWithResourceType(Type resourceType, TypeResourceMap<T> typeResourceMap)
        {
            _resourceType = resourceType;
            //_mappings = mappings;
            _typeResourceMap = typeResourceMap;
        }

        //private readonly IList<MemberResourceMapping> _mappings;

        public MapWithResourceType<T> Map<TValue>(Expression<Func<T, TValue>> memberExpression, string resourceName)
        {
            _typeResourceMap.Map(memberExpression, _resourceType, resourceName);
            return this;
        }
    }
}